perm filename SEC3.TEX[105,CSD] blob
sn#536188 filedate 1980-09-19 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00017 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00003 00002 %\sneakhead{Programming Superstitions} \sendindex{Superstitions}
C00005 00003 \specialbegin{Storage Variables and Assignment} \sendindex{Storage Variables} \sendindex{Assignment}
C00010 00004 In a program, a command which, when executed, gives the storage variable
C00016 00005 %This is INSERT E
C00017 00006 %This is INSERT G
C00019 00007 %This is INSERT L %after conditionals
C00020 00008 \specialbegin{Reading} \sendindex{Reading}
C00027 00009 %This is INSERT I
C00030 00010 %This is INSERTC
C00035 00011 \vfill\eject %This is INSERT J
C00040 00012
C00041 00013 %This is INSERT A
C00049 00014 \specialbegin{Conditional Commands} \sendindex{Conditional Commands}
C00062 00015 %This is INSERT M %for notes-after section on conditional commands
C00066 00016 %This is INSERT K
C00068 00017 \exercise
C00075 ENDMK
C⊗;
%\sneakhead{Programming Superstitions} \sendindex{Superstitions}
% The novice programmer will often find the behavior of his program
%difficult to diagnose. Experimentation may be helpful in leading him to
%discover where he misinterpreted the rules and definitions of the language.
%He should however be extremely cautious about deciding that the real rules
%of the language are different from those he has been told. Almost invariably
%this decision would be wrong. He would do better to take his difficulty to a
%member of the teaching staff or to an experienced Pascal programmer.
\specialbegin{Storage Variables and Assignment} \sendindex{Storage Variables} \sendindex{Assignment}
The harmonic numbers are:
$$\eqalign{H↓1 ⊗= 1\cr
H↓2 ⊗= 1 + {1\over2}\cr
H↓3 ⊗= 1 + {1\over2} + {1\over3}\cr
H↓4 ⊗= 1 + {1\over2} + {1\over3} + {1\over4}, etc.\cr}$$
In mathematical language, $$H↓n = {\sum↓{j=1}} {1\over j}$$
Evaluation of this series seems to be a natural candidate for iteration,
decomposing the problem
\wuncode{print the first 100 harmonic numbers}
into
\startcode
FOR J:=1 TO 100 DO
print the J-th harmonic number
\endcode
However, here we are stuck, even if we realize that $H↓j = H↓{j-1} + 1/j$,
and that we have just printed $H↓{j-1}$ at the time we want $H↓j, (j ≥ 2)$.
Let us, however, go as far as we can, making a special case of $H↓{1}$, because it
can not be computed from its predecessor.
\startcode
Print $H↓1$
FOR J:= 2 TO 100 DO
Print (1/J) + (the number most recently printed)
\endcode
What is needed here is a mechanism for saving the results of previous
computations. For this purpose, Pascal provides the ability to use variables
which hold the values resulting from previous computations. They are not
analogous to the variables of mathematics, which denote a single,
unknown value, which does not ``vary'' at all; nor to the iteration variables,
which run through a preordained set of values. We shall call them
{\sl storage variables}, \sendindex{storage variables} and a program may
change their values whenever desired.
We shall use upper case letters for storage variables and lower case letters
for mathematical variables.
We modify the above program by using a variable, {\tt SUM},
whose value will be changed as needed to remain
equal to the number most recently printed. We use comments extensively to
explain the significance of the information kept as the value of a variable.
Pascal requires that each storage variable used be explicitly created by
a special kind of command called a {\sl declaration}. \sendindex{declaration}
The declaration
\wuncode{VAR SUM : REAL} \sendindex{REAL}
creates a variable {\tt SUM} which is permitted to take any number as its value.
(``Real'' is used here in the sense, ``not imaginary''. What mathematicians
call real numbers are what the rest of us call numbers.) We might also have
occasion to declare
\wuncode{VAR A :INTEGER} \sendindex{INTEGER}
to create a variable {\tt A} which could take on only whole-number values,
whether positive, negative, or zero. (There are pragmatic reasons for having
several types of storage variables; the more restricted types, such as the
integer variables, typically require less of the computer's memory resources
for their representation, and the operations of arithmetic can often be
performed on them more rapidly.)
In a program, a command which, when executed, gives the storage variable
$\Vscr$ the value of the expression $\Escr$, is written
\wuncode{$\Vscr$:=$\Escr$}
which can be read ``assign the value of the expression $\Escr$ to the variable
$\Vscr$,''
or simply ``Set $\Vscr$ equal to $\Escr$.'' Such a command is called an
{\sl assignment}. \sendindex{assignment}
(If $\Vscr$ is an integer variable, $\Escr$ must be an integer expression. If
$\Vscr$ is a real variable, $\Escr$ may be either a real or an integer expression.)
Our program, as modified, now becomes
\startcode
PROGRAM HARMONICNUMBERS;
\sendnotes{RWF==>Cannot join to one line.Line would too long for TEX}
(* SUM WILL TAKE ON THE VALUES OF THE HARMONIC NUMBERS
H(1),$\ldotss$,H(100) *)
(* THE N-TH HARMONIC NUMBER H(N) = 1 + 1/2 + 1/3 + $\ldots$ + 1/N *)
VAR SUM : REAL;
J : INTEGER;
BEGIN
Give SUM the value 1 (= H$↓{1}$) and print H$↓{1}$;
FOR J:=2 TO 100 DO
(* SUM = H(J-1) *)
(Take (1/J) + the old value of SUM (= H$↓{J-1}$) as the
new value for SUM (= H$↓{J}$) and print SUM.)
END.
\endcode
We decompose
\wuncode{give SUM the value 1 and print H$↓{1}$;}
into
\startcode
SUM:= 1;
WRITELN(SUM);
\endcode
\noindent
and we change
\startcode
Take (1/j) + the old value of SUM (= H$↓{j-1}$) as
the new value for SUM (= H$↓{j}$) and print SUM
\endcode
\noindent
to
\startcode
BEGIN
SUM := 1/j + SUM;
WRITELN(SUM)
END
\endcode
\noindent
Our program is now
\startcode
PROGRAM HARMONICNUMBERS;
(* SUM TAKES ON THE VALUES OF THE HARMONIC NUMBERS H(1),$\ldotss$,H(100) *)
(* THE N-TH HARMONIC NUMBER H(N) = 1 + 1/2 + 1/3 + $\ldots$ + 1/N *)
VAR SUM : REAL;
J : INTEGER ;
BEGIN
SUM:= 1;
WRITELN(SUM);
FOR J:= 2 TO 100 DO
(* SUM = H(J-1) *)
BEGIN
SUM:= 1/J + SUM;
WRITELN(SUM)
END
END.
\endcode
\sendindex{storage variables} is
The general form of declarations which create storage variables
\startcode
VAR $\Iscr↓{11},\Iscr↓{21},\ldotss,\Iscr↓{n1}$ : $\Tscr↓1$;
$\Iscr↓{12},\Iscr↓{22},\ldotss,\Iscr↓{n2}$ : $\Tscr↓2$;
.
.
.
$\Iscr↓{1m},\Iscr↓{2m},\ldotss,\Iscr↓{nm}$ : $\Tscr↓m$;
\endcode
\noindent
where $\Tscr$ is the {\sl type} \sendindex{type} of value which the variables
$\Iscr↓{1},\Iscr↓{2},\ldots,\Iscr↓{n}, (n ≥ 1)$
take on. In addition to the types {\tt INTEGER} \sendindex{INTEGER}
and {\tt REAL}, \sendindex{REAL} we shall encounter others.
The reader should assume for the moment that all declarations must be
written at the beginning of the program, just after the header list, separated
by semicolons. {\tt VAR} \sendindex{VAR} is not repeated (see above example).
\rule{
For every storage variable, include a comment explaining what that variable does,
and, if necessary, why and how it does it.
}
%This is INSERT E
%\vfill %BUG. This produces a blank page. Why?
\example
\startcode
(* Summing the first 100 perfect squares. *)
PROGRAM SUMSQUARES (OUTPUT);
VAR I, (* ITERATION VARIABLE *)
SUM : INTEGER; (* SUM OF FIRST I PERFECT SQUARES *)
BEGIN
SUM := 0;
FOR I := 1 TO 100 DO
SUM := SUM + SQR(I);
WRITELN ('SUM OF FIRST 100 PERFECT SQUARES : ', SUM)
END.
\endcode
\topoutput
SUM OF FIRST 100 PERFECT SQUARES : 338350
\botoutput
%End of INSERT E
%This is INSERT G
\sendnotes{FINALCHECK: eject inserted to eliminate widow in 9/18 version.}
\vfill\eject
\example
\startcode
(* This program prints out a triangle of consecutive integers *)
PROGRAM TRIANGLE ( OUTPUT ) ;
VAR LINE , (* LINENUMBER *)
COLUMN , (* COLUMNNUMBER *)
COUNTER : INTEGER ; (* CURRENT NUMBER TO BE PRINTED *)
BEGIN
(* INITIALIZATION *)
COUNTER := 0 ;
(* PRINT TRIANGLE *)
FOR LINE := 1 TO 10 DO
BEGIN (* PRINT ONE LINE *)
FOR COLUMN := 1 TO LINE DO
BEGIN (* PRINT ONE NUMBER *)
COUNTER := COUNTER + 1 ;
WRITE ( COUNTER:3 )
END ;
WRITELN
END
END.
\endcode
\penalty500
\topoutput
1
2 3
4 5 6
7 8 9 10
11 12 13 14 15
16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 32 33 34 35 36
37 38 39 40 41 42 43 44 45
46 47 48 49 50 51 52 53 54 55
\botoutput
%END OF INSERT G
\vfill
\eject
%This is INSERT L %after conditionals
\exercise
What does this program draw?
\startcode
PROGRAM P ;
VAR S, A, DS, DA, L, C : INTEGER ;
BEGIN
S := 24 ;
A := 1 ;
DS := $-$1 ;
DA := 2 ;
FOR L := 0 TO 48 DO
BEGIN
FOR C := 1 TO S DO WRITE(' ') ;
FOR C := 1 TO A DO WRITE('*') ;
WRITELN ;
IF L = 24 THEN
BEGIN
DS := 1 ;
DA := $-$2
END ;
S := S + DS ;
A := A + DA
END
END .
\endcode
\endexercise
%End of INSERT L
\specialbegin{Reading} \sendindex{Reading}
The programs we have seen until now have each been capable of only a
single computation. To enable a program to solve a different problem each time
it is used, we have to provide it with different information each time it is
run. This information can be obtained from a file, or from the program's user
at his terminal. To get a number from the file called {\tt INPUT}, and assign
it to variable {\tt X}, use the command
\wuncode{READ(INPUT,X)}
or equivalently
\wuncode{READ(X)}
To get a number from the user at the terminal, and assign it to {\tt X}, use the
command
\wuncode{READ(TTY,X)}
where TTY (an abbreviation for teletype) is the Pascal name of the terminal.
When this command is executed, the program will wait for the user to type in the
required number, including a space or carriage return to end it.
A program to take a number from the input file, and print it along
with its square root, might be
\startcode
PROGRAM SQUAREROOT;
VAR X:REAL;
BEGIN
READ(X);
WRITELN(X, SQRT(X))
END.
\endcode
A similar program, taking the number from the terminal, could be
obtained by using the command
\wuncode{READ(TTY,X)}
However, this program would do nothing to tell the user that it was waiting
for him to type something, nor what it needed. A better program would first
print a message describing the desired input, and then execute a {\tt BREAK(TTY)}
command (which makes the program complete all terminal output before taking any input).
The complete program might be:
\startcode
PROGRAM SQUAREROOT;
VAR X:REAL;
BEGIN
WRITELN(TTY,'ENTER POSITIVE NUMBER FOR SQUARE ROOT');
BREAK(TTY);
READ(TTY, X);
WRITELN (X, SQRT(X))
END.
\endcode
\noindent
When this program is run, the program types
\wuncode{ENTER POSITIVE NUMBER FOR SQUARE ROOT}
If the user then types 2, followed by a {\tt RETURN}, the program puts
\wuncode{2 1.414214}
in the output file.
Usually, a program will need several pieces of information from the user.
It is usually advisable for the program to print a request for each, before
executing a read command. (This is called {\sl prompting} \sendindex{prompting}
the user.) A program to get two numbers, printing the square root of the first
and the square of the second, might be:
\startcode
PROGRAM P;
(declarations)
BEGIN
WRITELN(TTY, 'SQUARE ROOT OF'); (* OUTPUT TO TERMINAL *)
BREAK(TTY);
READ (TTY, X);
WRITELN('SQUARE ROOT OF', X, '=', SQRT(X)); (* OUTPUT TO FILE *)
WRITELN (TTY, 'SQUARE OF'); (* OUTPUT TO TERMINAL *)
BREAK(TTY);
READ (TTY, X);
WRITELN ('SQUARE OF', X, '=', X*X) (* OUTPUT TO FILE *)
END
\endcode
Alternatively, to present results at the terminal, the second and fourth
{\tt WRITELN} \sendindex{WRITELN} commands could be changed to
\wuncode{WRITELN (TTY, '=', SQRT (X));}
and
\wuncode{WRITELN (TTY, '=', X*X).}
When this second version of the program is executed, the results printed
at the terminal might be
\topoutput
SQUARE ROOT OF
2
= 1.414214
SQUARE OF
11
= 121
\botoutput
\noindent
where the user typed the {\tt 2} and {\tt 11}, the rest being printed by the
program.
It is important that a program to be used from a terminal should
{\sl prompt} the user with a description of each desired datum.
It is also important to include all input data in the output file, to confirm
the correctness of the data entry.
\rule{
An explanatory prompt should precede all terminal input operations.
It should be clear to a user who does not know the program details.
All input data should appear in the output file. This is done to protect
against the possibility that the user made a typing error. Such a repetition
of input in the output is called an {\sl echo}. \sendindex{echo}
}
%This is INSERT I
\sendnotes{FINALCHECK: eject inserted to eliminate widow 9/18.}
\vfill\eject
\example
\startcode
(* A PROGRAM TO COMPUTE AND PRINT THE RUNNING BALANCE OF A BANK *)
(* ACCOUNT. *)
(* INPUT : THE NUMBER OF CHECKS TO BE ENTERED IN THE BALANCE *)
(* THE INITIAL BALANCE *)
(* THE AMOUNT OF EACH INDIVIDUAL CHECK *)
%p8e1 goes here
PROGRAM BALANCE ( INPUT* , OUTPUT ) ;
VAR I,
COUNT : INTEGER ; (* NUMBER OF CHECKS *)
CHECK, (* AMOUNT OF A CHECK *)
BALANCE : REAL ; (* BALANCE OF ACCOUNT *)
BEGIN
(* READ INITIAL DATA *)
READ ( COUNT ) ;
READ (BALANCE ) ;
(* PRINT INITIAL DATA AND HEADER *)
WRITELN (' INITIAL BALANCE :',BALANCE:8:2 ) ;
WRITELN (' NUMBER OF CHECKS :',COUNT:5 ) ;
WRITELN ;
WRITELN (' CHECK NO. AMOUNT BALANCE' ) ;
WRITELN ('---------------------------------' ) ;
(* PROCESS THE CHECKS *)
FOR I := 1 TO COUNT DO
BEGIN
READ ( CHECK ) ;
BALANCE := BALANCE - CHECK ;
WRITELN ( I:10 , CHECK:10:2 , BALANCE:12:2 )
END
END.
\startcode
Input :
--------
4
234.60
125.00
4.50
61.05
5.00
\endcode
\topoutput
INITIAL BALANCE : 234.60
NUMBER OF CHECKS : 4
CHECK NO. AMOUNT BALANCE
---------------------------------
1 125.00 109.60
2 4.50 105.09
3 61.05 44.05
4 5.00 39.05
\botoutput
%This is the end of INSERT I
%This is INSERTC
\example
\sendnotes{RWF==> end of definite iteration?}
Write a Pascal program to read from a file the coefficients of a polynomial, and a
point at which to evaluate it, and print out the result of the evaluation. A
line in the file like
$$3.0\quad2\quad4.0\quad5.0\quad6.0$$
\noindent
designates the polynomial $4x↑2 + 5x + 6$ with $x = 3$, giving an answer of $57$;
while
$$2.3\quad 4\quad 1.2\quad -3.4\quad 4.5\quad 0.0\quad 6.7$$
\noindent
calls for $1.2x↑4 $-$ 3.4x↑3 + 4.5x↑2 + 6.7$ where $x = 2.3$ (about $22.7$). The
second number in each specification is the degree of the polynomial, and it is
followed by (degree $+ 1$) coefficients (including explicit zeroes, if any). All
of these numbers are in {\tt REAL} format, except for the degree, which is an
{\tt INTEGER}. The complete file consists of an integer telling how many such
lines there are, followed by the lines themselves. For example:
\startcode
40
3.0 2 4.0 5.0 6.0
2.3 4 1.2 -3.4 4.5 0.0 6.7
{\rm thirty-eight more lines}
\endcode
To make the program as versatile as possible, you should use the following
approach (based on Horner's rule): Note that $$Ax↑3 + Bx↑2 + Cx + D =
(((Ax) + B)x + C)x + D;$$ in general:
$$\twoline{R↓nx↑n + R↓{n-1}x↑{n-1} + \cdotss + R↓2x↑2 + R↓1x + R↓0}{2pt}{\null =
(\cdotss(((R↓nx) + R↓{n-1})x + R↓{n-2})x + \cdotss + R↓1)x + R↓0 .}$$
\noindent
This suggests a method of evaluating the polynomial on the fly, as the coefficients
are being read in: repeatedly calculate a new result by taking the old result,
multiplying by $x$ and adding the new coefficient, This, correctly
programmed, works for polynomials of any degree, including zero.
The output should include a reasonable facsimile of the input polynomial as
well as the result. For instance the output for the two lines above might be:
\startcode
( 4.0 X$\up$2 + 5.0 X$\up$1 + 6.0 ) AT X=30 IS 56.9
( 1.2 X$\up$4 + -3.4 X$\up$3 + 4.5 X$\up$2 + 0.0 X$\up$1 + 6.7 ) AT X=2.3 IS 22.7
\endcode
\noindent
To print a {\tt REAL} number, {\tt R}, neatly (i.e. without an exponent,
and with a specified number of digits to the right of the decimal point), you
might try:
\wuncode{WRITE(R:TRUNC(LOG(ABS(R)+1))+3+DP:DP)}
where {\tt DP} is the number of decimal places you want displayed (one should
be enough for this assignment).
%rewrite
\sendnotes{Professor Floyd to rewrite this part later}.
That says ``write out {\tt R} with just enough room for the sign, all the digits to
the left of the decimal point, the decimal point itself, and {\tt DP} places to
the right of the decimal point.'' You may find your answers off by one in the
least significant place, due to rounding errors. Also, the ``$\up$'' character
may look more like ``{\tt ∂}'' on your terminal and/or printout.
%This is the end of INSERT C
\vfill\eject %This is INSERT J
\startcode
(* EVALUATION OF POLYNOMIALS USING HORNER'S RULE. *)
(* INPUT : FIRST LINE : NUMBER OF POLYNOMIALS TO BE EVALUATED *)
(* NEXT LINES : X DEGREE COEF COEF COEF ... COEF *)
(* X : POINT OF EVALUATION *)
(* DEGREE : DEGREE OF POLYNOMIAL*)
(* COEF : POLYNOMIAL COEFFICIENTS FROM *)
(* HIGH ORDER TO LOW ORDER *)
(* OUTPUT : FACSIMILE OF INPUT , EVALUATED POLYNOMIAL *)
PROGRAM POLYEVAL ( INPUT* , OUTPUT ) ;
CONST DP = 1 ; (* NUMBER OF DECIMAL PLACES IN OUTPUT *)
VAR NUMBER, (* NUMBER OF POLYNOMIALS *)
DEGREE, (* DEGREE OF POLYNOMIAL *)
I, J : INTEGER ; (* ITERATION VARIABLES *)
X, (* EVALUATION POINT *)
COEF, (* POLYNOMIAL COEFFICIENT*)
VALUE : REAL ; (* (RUNNING) VALUE OF POLYNOMIAL IN X *)
\allowbreak
BEGIN
(* READ NUMBER OF LINES *)
READ ( NUMBER ) ;
(* EVALUATE NUMBER POLYNOMIALS *)
FOR I := 1 TO NUMBER DO
BEGIN (* INITIAL INPUT-OUTPUT AND INITIALIZATION OF VALUE *)
READ ( X, DEGREE ) ;
WRITE ( '( ' ) ;
VALUE := 0.0 ;
(* EVALUATE POLYNOMIAL *)
FOR J := DEGREE DOWNTO 0 DO
BEGIN (* READ/WRITE ONE COEFFICIENT, AND APPLY ONE STEP OF
OF HORNER'S RULE *)
READ ( COEF ) ;
WRITE ( COEF:TRUNC(LOG(ABS(COEF)+1))+3+DP:DP ) ;
IF J <> 0 THEN WRITE ( ' X∂', J:1, ' + ' ) ;
VALUE := VALUE*X + COEF
END ; (* J ITERATION *)
(*FINAL OUTPUT *)
WRITELN ( ' ) AT X = ' , X:TRUNC(LOG(ABS(X)+1))+3+DP:DP,
' IS ' , VALUE:TRUNC(LOG(ABS(VALUE)+1))+3+DP:DP )
END (* I ITERATION *)
END. (* POLYEVAL *)
\endcode
\vfill
\topoutput
( 4.0 X∂2 + 5.0 X∂1 + 6.0 ) AT X = 3.0 IS 56.9
( 1.2 X∂4 + -3.4 X∂3 + 4.5 X∂2 + 0.0 X∂1 + 6.6 ) AT X = 2.3 IS 22.7
( 1.0 X∂1 + 0.0 ) AT X = 0.0 IS 0.0
( 0.0 X∂2 + 0.0 X∂1 + 0.1 ) AT X = 999.0 IS 1008.2
( 1.0 X∂5 + -1.0 X∂4 + 1.0 X∂3 + -1.0 X∂2 + 1.0 X∂1 + -1.0 ) AT X = 0.0
IS -0.9
( 1.0 X∂5 + -1.0 X∂4 + 1.0 X∂3 + -1.0 X∂2 + 1.0 X∂1 + -1.0 ) AT X = 200.0
IS 318407961726.1
( 1.0 X∂5 + -1.0 X∂4 + 1.0 X∂3 + -1.0 X∂2 + 1.0 X∂1 + -1.0 ) AT X = 2.0
IS 20.9
( -324.2 X∂2 + 5123.8 X∂1 + 0.0 ) AT X = 1234.5 IS -487799942.4
( 3.3 X∂2 + 6.6 X∂1 + 10.0 ) AT X = 0.3 IS 12.5
( -222.9 ) AT X = 284.7 IS -222.9
( -222.9 X∂1 + -223.0 ) AT X = 284.7 IS -63824.3
( -222.9 X∂2 + 334.0 X∂1 + -444.9 ) AT X = 284.7 IS -17981683.3
\botoutput
%This is the end of INSERT J
\exercise
Write a program which prints a rectangle of asterisks after reading its
height and width. Use prompting and echoes.
\endexercise
\exercise
Write a program to add a series of numbers from the terminal,
printing the cumulative sums. The set of numbers to be added should be
preceded by a number giving the size of the set. Use prompting and echoes.
\endexercise
%This is INSERT A
\specialbegin{LOTS Pascal Note}
\sendindex{LOTS}
A Pascal program, by its {\tt WRITE} and {\tt WRITELN} commands,
sends numbers and characters to files in a form suitable for printing. If
no explicit names are given to these files, it is assumed that
all output goes to one file which is called {\tt OUTPUT}. This has a
disadvantage. If my last program left its results in the file called
{\tt OUTPUT}, and my current program writes its results there, I will
thereby lose the older results. Furthermore, naming the file
{\tt OUTPUT} gives no hint of what the results are about. And if I run
the same program again with different input, the new results replace and
destroy the old ones.
It is desirable to be able to name, each time the program is
run, the LOTS file which receives the results of your program. In its
simplest form,
to do this one writes the first line of the program in the form
\wuncode{PROGRAM $\Iscr$(OUTPUT);}
\noindent
where $\Iscr$ is the name of the program. When the program is executed, it
will begin by asking the user at the terminal to provide the filename (in
a LOTS directory) for the output file.
A Pascal program may write information in several different files,
each time it is run. Each such file generally has two names: in Pascal
that name by which it is known to the program, a name which is built into the
program; and that name by which it is known to TOPS-20, a name provided
when the program is executed. We shall call these names the Pascal name and
the directory name of the file, respectively. Most Pascal names appear
explicity in the first line of the program, in the form
\wuncode{PROGRAM $\Iscr↓0 (\Iscr ↓1, \Iscr ↓2, \ldotss, \Iscr ↓n)$;}
\noindent
where $\Iscr↓0$ is the name of the program, and $\Iscr↓1, \Iscr↓2, \ldotss, \Iscr↓n$
are the Pascal names of the files it uses. They also appear explicitly in
{\tt WRITE} and {\tt WRITELN} commands;
\wuncode{WRITE($\Iscr, \Escr$)}
\noindent
writes the value of expression $\Escr$ to the file with Pascal name $\Iscr$.
\samecode{
WRITE($\Iscr,\Escr↓1,\Escr↓2,\ldotss,\Escr↓n$)⊗WRITE($\Iscr,\Escr↓1$);\cr
\qquad ⊗ WRITE($\Iscr,\Escr↓2$);\cr
⊗\qquad .\cr
⊗\qquad .\cr
⊗\qquad .\cr
\qquad ⊗ WRITE($\Iscr, \Escr↓n$)\cr\noalign{\vskip 6pt}
WRITELN($\Iscr,\Escr↓1,\Escr↓2\ldotss,\Escr↓n$)⊗WRITE($\Iscr,\Escr↓1,\Escr↓2,\ldotss,\Escr↓n$);\cr
\qquad ⊗WRITELN($\Iscr$)\cr
}%end twocolcode.
When a program is executed, the user is asked for the directory names of all
the files for which Pascal names appear in the program head. The directory
names may be any TOPS-20 file name. As a convenience, the names
``{\tt TTY: }'' and ``{\tt LPT: }'' may be given as directory names (note
the colons); they are not actually files, but refer to the terminal screen
and line printer respectively. Use of ``{\tt TTY: }'' as a directory name has
pitfalls; when the terminal is also being used as an input source by the
program, output may fail to appear on the terminal screen at the desired time.
Two Pascal names of files may be implicit, unmentioned in the
program head: {\tt OUTPUT} and {\tt INPUT}. If no explicit Pascal file
name is given in a WRITE or WRITELN command, {\tt OUTPUT} is assumed:
\samecode{
WRITE($\Escr↓1,\ldotss,\Escr↓n$)⊗WRITE(OUTPUT,$\Escr↓1,\ldotss,\Escr↓n$)\cr
}%end samecode.
\noindent
If no explicit Pascal file name is given in a {\tt READ} command, {\tt INPUT}
is assumed:
\samecode{
READ($\Vscr↓1,\ldotss,\Vscr↓n$)⊗READ(INPUT,$\Vscr↓1,\ldotss,\Vscr↓n$)\cr
}%end samecode.
\noindent
When {\tt INPUT} and {\tt OUTPUT} are used as implicit Pascal names, the
corresponding directory names are also assumed to be {\tt INPUT} and
{\tt OUTPUT}. For flexibility, it therefore is usually better to explicitly
name {\tt OUTPUT} and {\tt INPUT} in the program head. When {\tt INPUT}
appears in the program head, it must be immediately followed by an
asterisk:
\wuncode{PROGRAM ${\Pscr}$ (INPUT*,OUTPUT)}
When it is intended that a {\tt WRITE} command always send its
results to the terminal screen, it is possible to use another implicit
Pascal name:{\tt ``TTY''} (unlike the correponding directory name, it
contains no colon). Since such output leaves no permanent record, it is
typically used to inform and direct the user.
%This is the end of INSERT A
\specialbegin{Conditional Commands} \sendindex{Conditional Commands}
Pascal offers a type of command which tests whether some condition is true
or false, and executes one command or another accordingly. The general form
of such commands is
\wuncode{IF $\Escr$ THEN $\Cscr ↓{1}$ ELSE $\Cscr ↓{2}$}
or
\wuncode{IF $\Escr$ THEN $\Cscr ↓{1}$}
where $\Escr$ is a condition which can be tested. If $\Escr$ is true, $\Cscr$$↓{1}$ is
executed; if $\Escr$ is false, $\Cscr ↓{2}$ is executed in the first case, and nothing is
done in the second.
The conditions \sendindex{conditions} may be of any of the forms
\twocolalign{
$\Escr ↓{1}$ = $\Escr ↓{2}$⊗\cr
$\Eone$ <> $\Etwo$⊗meaning $\Eone ≠ \Etwo$\cr
$\Escr ↓{1}$ < $\Escr ↓{2}$⊗\cr
$\Escr ↓{1}$ <= $\Escr ↓{2}$⊗(meaning $\Escr ↓{1} ≤ \Escr ↓{2}$)\cr
$\Escr ↓{1}$ > $\Escr ↓{2}$⊗\cr
$\Escr ↓{1}$ >= $\Escr ↓{2}$⊗(meaning $\Escr ↓{1} ≥ \Escr ↓{2}$)\cr
{\tt ODD(}$\Escr${\tt )}⊗(true if and only if the integer $\Escr$ is an odd number)\cr
}%end of twocolalign
Expressions such as these, having as values {\tt TRUE} or {\tt FALSE} rather than a number,
are called {\sl Boolean expressions} \sendindex{Boolean expressions} (after logician George Boole).
\example
To print a table of squares, starting a new line after every fifth number,
we keep a variable with which we count how many squares have been printed on
the current line. When the count reaches five, we start a new line and reset
the count to zero.
\startcode
(heading, declarations)
BEGIN
COUNT:= 0;
FOR I:= 1 TO 93 DO
BEGIN
WRITE(I*I);
COUNT := COUNT+1;
IF COUNT = 5 THEN
BEGIN
WRITELN;
COUNT:= 0
END
END
END.
\endcode
Notice the difference between {\tt =} and {\tt := ;} the first is used in conditions,
the second in assignment.
\example
To print the picture of a square with a blank diagonal as shown below
\topoutput
****
* ***
** **
*** *
****
\botoutput
we could write
\startcode
FOR R:=1 TO 5 DO (* 5 ROWS *)
BEGIN
FOR C:=1 TO 5 DO (* 5 CHARACTERS PER ROW *)
IF R=C THEN
WRITE(' ') (* ON THE DIAGONAL *)
ELSE
WRITE('*'); (* NOT ON DIAGONAL *)
WRITELN
END
\endcode
\noindent
We could, in this case, have designed the program without conditional commands,
by viewing the pattern as a pair of triangles separated by a blank diagonal
line:
\startcode
FOR R := 1 TO 5 DO
BEGIN
FOR C := 1 TO R-1 DO (*SKIPS IF R = 1*)
WRITE('*');
WRITE(' ');
FOR C := 1 TO 5-R DO
WRITE('*');
WRITELN
END
\endcode
\example
In the game of chess, the rook is a piece which can move horizontally or
vertically, as far as desired (unless blocked by another piece). We consider
the problem of drawing a diagram to show the rook at a specified place on the
chessboard, with all the squares to which the rook might move marked with
asterisks. An example of such a diagram with the rook in the fourth row and
the third column is:
\topoutput
..*.....
..*.....
..*.....
**R*****
..*.....
..*.....
..*.....
..*.....
\botoutput
\noindent
The large number of dots and asterisks suggests using an iteration, but since
they are intermixed there is little hope of writing separate iterations to
print dots and to print asterisks. Instead, we iterate a conditional command
which, when executed, prints one character. It chooses which character to
print in each position of the board by testing whether the position is occupied
or attacked by the rook. The iterative structure of the program is
\startcode
VAR R,C : INTEGER; (* ROW AND COLUMN COUNTERS *)
ROOKROW,ROOKCOL : INTEGER; (* NOTE DESCRIPTIVE NAMES *)
WRITE(TTY,'ENTER ROW ');
BREAK(TTY);
READ(TTY,ROOKROW);
WRITE(TTY,'ENTER COLUMN ');
BREAK(TTY);
READ(TTY,ROOKCOL);
FOR R:=1 STEP 1 UNTIL 8 DO (* DRAW THE R-TH ROW *)
BEGIN
FOR C:=1 STEP 1 UNTIL 8 DO
Print the correct character for column C of row R;
WRITELN
END
\endcode
\noindent
The printing command required above must print ``{\tt R}'' if
{\tt R = ROOKROW} and
{\tt C = ROOKCOL}; otherwise, it must print ``{\tt *}'' on the rook's row
{\tt (R = ROOKROW)} and on the rook's column {\tt (C = ROOKCOL)}, and
``{\tt .}'' elsewhere. The printing command needed can be written:
\startcode
IF R=ROOKROW THEN
(* PRINT ONE CHARACTER ON ROOK'S ROW *)
IF C=ROOKCOL THEN WRITE('R')
ELSE WRITE('*')
ELSE (* NOT ON ROOK'S ROW *)
IF C=ROOKCOL THEN WRITE('*')
ELSE WRITE('.')
\endcode
\noindent
It is essential to the above command that whenever it is executed, it prints
exactly one character. The first condition chooses between two commands; each
of them, if executed, prints one character, as desired. What would happen if
the above printing command were designed so that when {\tt R = ROOKROW}
it would
print the entire 8 character row? (If in doubt, try it.)
Often, when a long series of actions is desired, but the actions are a
mixture of several different kinds, a programmer will write an iterative
command, iterating a conditional command which selects the appropriate action
for each value of the iteration variable.
The grammar of conditional commands permits an apparently ambiguous
situation to arise. Suppose we wanted to write a command to test variables
{\tt X} and {\tt Y}, printing {\tt 2} if {\tt X $≠$ 0}, printing
{\tt 1} if {\tt X = 0} and {\tt Y = 0},
and doing nothing if {\tt X = 0} but {\tt Y $≠$ 0}. We might write:
\startcode
IF X = 0 THEN
IF Y = 0 THEN WRITE(1)
ELSE WRITE(2)
\endcode
\noindent
On the other hand, if we wanted to do nothing if {\tt X $≠$ 0}, print {\tt 1} if
{\tt X = 0} and {\tt Y = 0}, and print {\tt 2} if {\tt X = 0}
and {\tt Y $≠$ 0}, we might write
\startcode
IF X = 0 THEN
IF Y = 0 THEN WRITE(1)
ELSE WRITE(2)
\endcode
\noindent
These are the same command, except for the spacing, which is not semantically
significant. Yet the first supposedly prints {\tt 2} if {\tt X $≠$ 0},
while the second does not print anything if {\tt X $≠$ 0}. Which does the
command mean? It has the second meaning; where an {\tt ELSE} \sendindex{ELSE}
could be matched with more than one {\tt IF}, \sendindex{IF} it is matched with
the {\sl nearest} possible one. We could force the {\tt ELSE} to
match the first {\tt IF}, as we intended in the first program, by ``hiding'' the second
{\tt IF} inside a compound statement:
\startcode
IF X = 0 THEN
BEGIN
IF Y = 0 THEN WRITE(1)
END
ELSE WRITE(2)
\endcode
As a general rule, between any {\tt IF} and its matching {\tt ELSE}, there must be the same
number of {\tt IF}s as {\tt ELSE}s, not counting those ``hidden'' inside blocks.
\samecode{
IF $\Eone$ THEN⊗IF $\Eone$ THEN\cr
\quad IF $\Etwo$ THEN $\Cone$⊗\quad BEGIN\cr
\quad ELSE $\Ctwo$⊗\quad IF $\Etwo$ THEN $\Cone$\cr
⊗\quad ELSE $\Ctwo$\cr
⊗\quad END\cr
}%end of samecode
%This is INSERT M %for notes-after section on conditional commands
\sendnotes{FINALCHECK: eject inserted to eliminate widow 9/18.}
\sendnotes{DPB ==> RWF: The - signs in the Quad eqn prog are in math mode. Why?}
\vfill\eject
\example
\startcode
(* SOLUTION OF A QUADRATIC EQUATION : A X X + B X + C *)
PROGRAM QUADEQUATION ( INPUT*, OUTPUT ) ;
VAR A, B, C, (*COEFFICIENTS OF EQUATION*)
DISCR : REAL ; (*DISCRIMINANT OF EQUATION *)
BEGIN
(* INPUT AND INITIAL OUTPUT *)
READ ( A, B, C ) ;
WRITELN (' SOLUTION OF QUADRATIC EQUATION',
A:8:4, ' Xβ2 + ', B:8:4, ' X + ', C:8:4, ' = 0.0000 ' ) ;
WRITELN ;
(* SOLUTION OF EQUATION*)
IF A = 0 THEN (* LINEAR EQUATION *)
IF B = 0 THEN (* DEGENERATE EQUATION C = 0 *)
IF C = 0 THEN
WRITELN (' INFINITELY MANY SOLUTIONS' )
ELSE WRITELN (' NO SOLUTIONS' )
ELSE (* REAL LINEAR EQUATION B X + C = 0 *)
WRITELN (' SINGLE SOLUTION :',($-$C/B):8:4 )
ELSE (* PROPER QUADRATIC EQUATION *)
BEGIN
DISCR := SQR(B)$-$4.0*A*C ;
IF DISCR = 0 THEN
WRITELN (' TWO IDENTICAL SOLUTIONS :',($-$B/(2.0*A)):8:4 )
ELSE
IF DISCR > 0 THEN
BEGIN
WRITELN (' TWO REAL SOLUTIONS :',
(($-$B$-$SQRT(DISCR))/(2.0*A)):8:4 );
WRITELN (' ',
(($-$B+SQRT(DISCR))/(2.0*A)):8:4 )
END
ELSE
BEGIN
WRITELN (' TWO COMPLEX SOLUTIONS :',
($-$B/(2.0*A)):8:4,' + I ',(SQRT($-$DISCR)/(2.0*A)):8:4);
WRITELN (' ',
($-$B/(2.0*A)):8:4,' - I ',(SQRT($-$DISCR)/2.0*A):8:4);
END
END
END.
\endcode
%This is INSERT K
%After conditionals
%part8.tex goes after conditionals
\example
This program reads the identification numbers and scores of one
hundred players in a tournament, and prints out the numbers and scores of
the two best players. (In case of ties, it treats the first player as the
winner.)
\startcode
%p8e3 goes here
PROGRAM TOPTWO ;
VAR I, SCORE, BEST, SECOND, NUMBER, NUMBER1, NUMBER2: INTEGER;
BEGIN
BEST := - 1 ; SECOND := - 1 ;
NUMBER1 := 0 ; NUMBER2 := 0 ;
FOR I := 1 TO 100 DO
BEGIN
READ (NUMBER , SCORE) ;
IF SCORE > SECOND THEN
IF SCORE > BEST THEN
BEGIN
SECOND := BEST ;
BEST := SCORE ;
NUMBER2 := NUMBER1 ;
NUMBER1 := NUMBER ;
END
ELSE
BEGIN
SECOND := SCORE ;
NUMBER2 := NUMBER
END ;
END ;
WRITELN(NUMBER1, BEST, NUMBER2, SECOND)
END.
\endcode
%This is the end of INSERT K
\exercise
In the game of chess, the queen is a piece which can move
horizontally, vertically, or diagonally. Write a program to read, from the
terminal, the position of the queen (the number of the row and the number
of the column) and to print a diagram showing to which squares the queen can
move. For example, such a diagram showing the possible queen moves from
row 4, column 3 is:
\endexercise
\topoutput
..*..*..
*.*.*...
.***....
**Q*****
.***....
*.*.*...
..*..*..
..*...*.
\botoutput
\exercise
Write a program to keep track of a checking account. Let the
initial balance be zero. The first number read in is the total
number of checks and deposits. The remaining data are the amounts of checks
(negative numbers) and deposits (positive numbers). For each datum, the
program should print the datum and the balance after processing the datum
by adding it to the balance. Then change the program, to impose sevice
charges of \$0.05 per deposit and \$0.10 per check.
\endexercise
\exercise
Same as above, but waiving service charges on accounts which have
a balance of at least \$300.00 after the deposit or check.
\endexercise
\exercise
Same as above, but taking into account overdrafts, according to
the following rules:
\bitem Service charges of \$0.05 per deposit, \$0.10 per check paid,
waived if the balance, before figuring in the service charge, is
at least \$300.
\bitem Penalty charge of \$3.00 per overdraft (a check that would, if cashed,
leave the balance negative, including service charges).
\bitem Checks which would leave a balance less than -\$50.00 are not honored
(i.e. paid). Take into account the effect of service charges in making
this decision, but remember to charge only the penalty, and not the
service charge, for a check which is not paid.
\noindent
Warning: It is easy to make a mistake in programming the above policy.
Remember that the program must accept deposits even to overdrawn accounts, and
that the service charge on a check may overdraw the account. Read the rules
{\sl very} carefully. Try to think like a banker.
\endexercise